//  IDVI 1.0 source copyright 1996 Garth A. Dickie
//
//  This source is free for non-commercial use.  No warranty, etc.
//  Please acknowledge reuse by including the line:
//
//  "Based in part on IDVI 1.0 source copyright 1996 Garth A. Dickie"
//
//  in your documentation and source code.  For commercial use or
//  distribution, please contact the author.  Please also send
//  questions, comments, bug reports, or fixes.
//
//  Best Regards,
//  Garth A. Dickie
//  dickie@elastic.avid.com

package ibook.v10.idvi.display;

import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;

//      Mouse events not used by the child are used to make the
//      ActionView act like a button.  Appropriate methods in the
//      associated ActionBlockGroup are called as the mouse enters
//      and exits the button area, and when the button is selected.

abstract class ActionView extends FilterView {
    private ActionBlockGroup    group;
    private ViewPanel           panel;
    private boolean             selected;
    private boolean             childDoneLoading;
    private Color               unselectedAdornmentColor;
    private Color               unselectedColor;
    private Color               selectedColor;
    private int                 unselectedAdornmentIndex;
    private int                 unselectedColorIndex;
    private int                 selectedColorIndex;

    private DVIRectangle        boundsScratch = new DVIRectangle( );

    ActionView(
            ScaledColorScheme colorScheme, int scale, ViewPanel panel,
            ActionBlockGroup group, Block blockChild,
            int unselectedAdornmentIndex, int unselectedColorIndex, int selectedColorIndex,
            boolean selected, boolean childDoneLoading ) {
        
        super( colorScheme, scale, panel, blockChild );

        this.panel = panel;
        this.group = group;
        this.unselectedAdornmentIndex = unselectedAdornmentIndex;
        this.unselectedColorIndex = unselectedColorIndex;
        this.selectedColorIndex = selectedColorIndex;
        this.selected = selected;
        this.childDoneLoading = childDoneLoading;

        unselectedAdornmentColor = colorScheme.getForegroundColor( unselectedAdornmentIndex );
        unselectedColor = colorScheme.getForegroundColor( unselectedColorIndex );
        selectedColor = colorScheme.getForegroundColor( selectedColorIndex );
    }

    int getFlags( ) {
        return View.kFlagGetsMouseEvents | super.getFlags( );
    }

    //  setSelected( ) is called by our ActionBlock.

    void setSelected( boolean selected ) {
        if( selected != this.selected ) {
            this.selected = selected;
            if( parent != null ) {
                parent.childBounds( boundsScratch, indexInParent );
                parent.repaint( boundsScratch, indexInParent, kRepaintDelayInteraction );
            }
        }
    }

    void childDoneLoading( ) {
        this.childDoneLoading = true;

        if( parent != null ) {
            parent.childBounds( boundsScratch, indexInParent );
            getAdornmentBounds( boundsScratch );
            parent.repaint( boundsScratch, indexInParent, kRepaintDelayProgressive );
        }
    }

    int getBounds( DVIRectangle bounds, int scale, int x, int y, Block block ) {
        int expansion = super.getBounds( bounds, scale, x, y, block );
        addAdornmentBounds( bounds );

        return expansion;
    }

    //  We have to be careful in the paint( ) method because our child
    //  may (probably will) modify the bounds rectangle.  So we draw the
    //  underline first, and then our child.

    void paint( Graphics g, int color, DVIRectangle bounds, DVIRectangle clip, int yOffset ) {
        if( childDoneLoading ) {
            g.setColor( selected ? selectedColor : unselectedAdornmentColor );
            paintAdornment( g, color, bounds, clip );
        }

        removeAdornmentBounds( bounds );
        if( bounds.intersects( clip )) {
            int newColor = selected ? selectedColorIndex : unselectedColorIndex;
            super.paint( g, newColor, bounds, clip, yOffset );
        }

    }

    //  Mouse tracking routines

    private boolean childSelecting = false;
    private boolean selecting = false;
    private boolean inside = false;

    void mouseEnter( int x, int y ) {
        inside = true;

        panel.getAppletContext( ).showStatus( group.getHREF( ));

        if( selecting )
            group.setSelected( true );
        else
            super.mouseEnter( x, y );
    }

    void mouseMove( int x, int y ) {
        super.mouseMove( x, y );        //  allow tracking enter and exit in child.
    }

    boolean mouseDown( int clickCount ) {
        if( super.mouseDown( clickCount )) {
            childSelecting = true;
        } else {
            selecting = true;
            group.setSelected( true );
        }

        return true;
    }

    void mouseDrag( int x, int y ) {
        if( childSelecting )
            super.mouseDrag( x, y );
    }

    boolean mouseUp( int modifiers ) {
        boolean result = false;

        if( selecting ) {
            selecting = false;

            if( inside ) {
                String target;

                if(( modifiers & Event.ALT_MASK ) != 0 ) {
                    target = "_blank";
                } else {
                    target = group.getTarget( );
                    if( target == null )
                        target = "_self";
                }
                    
                panel.showDocument( group.getHREF( ), target );
                group.setSelected( false );
            }

            result = true;
        } else if( childSelecting ) {
            childSelecting = false;

            result = super.mouseUp( modifiers );
        }

        return result;
    }

    void mouseExit( ) {
        inside = false;

        panel.getAppletContext( ).showStatus( "" );

        if( selecting )
            group.setSelected( false );
        else
            super.mouseExit( );
    }

    //  childAddedToBounds( ) and childBounds( ) are used to pass bounds information
    //  between our parent and our child; we catch them and do the appropriate thing
    //  in each case to deal with the space used by our added underline.
    //
    //  Some care is needed in childAddedToBounds( ) because the newBounds parameter may
    //  actually be the DVIRectangle that is used to store the bounds of the child.  We
    //  could create a copy every time this method is called, but instead we are just
    //  careful to undo our modifications before we return.

    void childAddedToBounds( DVIRectangle newBounds, int expansion ) {
        addAdornmentBounds( newBounds );
        super.childAddedToBounds( newBounds, expansion );
        removeAdornmentBounds( newBounds );
    }

    void childBounds( DVIRectangle childBounds, int childIndex ) {
        super.childBounds( childBounds, childIndex );
        removeAdornmentBounds( childBounds );
    }

    //  methods having to do with the adornment of this ActionView, which is added
    //  by the subclasses.

    void paintAdornment( Graphics g, int color, DVIRectangle bounds, DVIRectangle clip ) {
    }

    void addAdornmentBounds( DVIRectangle bounds ) {
    }

    void removeAdornmentBounds( DVIRectangle bounds ) {
    }

    void getAdornmentBounds( DVIRectangle bounds ) {
    }

    //

    public String toString( ) {
        return super.toString( ) + ", selected = " + selected;
    }
}
